﻿#include <iostream>
#include <vector>
#include <string>

using namespace std;

/**
 * C++设计模式之建造者模式(Builder Pattern),
 * 这个给我感觉更像一个装配工厂，装配车间
 * 装配流程由Builder制定，具体装配由Director去调用Builder的派生类来生成产品
 */

//Product类
class Product {
private:
    std::vector<std::string> parts;
public:
    void Add(const std::string &part) {
        parts.push_back(part);
    }

    void Add(std::string &&part) {
        parts.emplace_back(std::move(part));
    }

    void Show() const {
        for (const auto &part: parts) {
            std::cout << part << std::endl;
        }
    }
};

//抽象builder类
class Builder {
public:
    Builder() = default;

    virtual ~Builder() = default;

    virtual void BuildHead() = 0;

    virtual void BuildBody() = 0;

    virtual void BuildHand() = 0;

    virtual void BuildFeet() = 0;

    virtual Product GetResult() = 0;
};

//具体胖人创建类
class FatPersonBuilder : public Builder {
private:
    Product product;
public:
    void BuildHead() override {
        product.Add("胖人头");//创建瘦人的头
    }

    void BuildBody() override {
        product.Add("胖人身体");//创建瘦人的身体
    }

    void BuildHand() override {
        product.Add("胖人手");//创建瘦人的手
    }

    void BuildFeet() override {
        product.Add("胖人脚");//创建瘦人的脚
    }

    Product GetResult() override {
        return product;
    }
};

//具体瘦人人创建类
class ThinPersonBuilder : public Builder {
private:
    Product product;
public:
    void BuildHead() override {
        product.Add("瘦人人头");//创建瘦人的头
    }

    void BuildBody() override {
        product.Add("瘦人身体");//创建瘦人的身体
    }

    void BuildHand() override {
        product.Add("瘦人手");//创建瘦人的手
    }

    void BuildFeet() override {
        product.Add("瘦人脚");//创建瘦人的脚
    }

    Product GetResult() override {
        return product;
    }
};

//Director类
class Director {
public:
    static void Construct(std::shared_ptr<Builder> &builder) {
        builder->BuildHead();
        builder->BuildBody();
        builder->BuildHand();
        builder->BuildFeet();
    }
};

int main() {
    auto director = std::make_unique<Director>();
    std::shared_ptr<Builder> b1 = std::make_shared<FatPersonBuilder>();
    std::shared_ptr<Builder> b2 = std::make_shared<ThinPersonBuilder>();

    director->Construct(b1);
    Product p1 = b1->GetResult();
    p1.Show();

    std::cout << "----------------------------" << std::endl;

    director->Construct(b2);
    Product p2 = b2->GetResult();
    p2.Show();
    std::cout << "----------------------------" << std::endl;

    return 0;
}
